import ProductAPI from '@/api/Product';
import ProductInfoAPI from '@/api/ProductInfo';
import { FieldCols, FormSection, mapField, useCall, useDebounceValue, useFormValue, useReq } from '@/components';
import InfoGroupEdit from '@/pages/product/AttachmentPage/components/InfoGroupEdit';
import { basename } from 'path';
import { arrayUnique, getAccept, optionsToMap, pick } from '@/utils';
import { Form, Spin } from 'antd';
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import { usePackageData } from './PackageContext';

function useProductCodesByPackageCode(packageData) {
  const infoData = packageData;

  const [productCodes, setProdCodes] = useState(null);
  useEffect(() => {
    if (infoData) {
      const { plans } = infoData;
      setProdCodes(arrayUnique(plans.flatMap((p) => p.requestProducts.map((r) => r.businessCode))));
    } else {
      setProdCodes(false);
    }
  }, [infoData]);

  return productCodes;
}

// 资料库附件类型集合
const attachmentTypes = [
  ['PI', '产品介绍'], // product introduce
  ['HN', '健康告知'], // healthy notice
  ['PN', '投保须知'], // policy notice
  ['FT', '费率表'], // fee table
  // ['QP', '职业类别表'], //
  ['CT', '现金价值表'], // cash value table
  ['BS', '支持银行'], // banks supported
  ['AS', '附加服务'], // addition services
  ['SP', '常见问题'], //
];
const titleMap = {
  ...optionsToMap(attachmentTypes, 1, 0),
  PE: 'Banner图',
  PC: '产品特色',
  MV: '产品介绍视频',
};

const singles = ['PE', 'MV', 'PC'];
const multiples = attachmentTypes.map((v) => v[0]);

function FilesForm({ form }) {
  const fields = useMemo(
    () =>
      multiples
        .map((showType) => [
          showType,
          null,
          InfoGroupEdit,
          {
            titleReadOnly: true,
            disableRichText: true,
            defaultTitle: titleMap[showType],
            uploadProps: { accept: getAccept('all'), multiple: true },
          },
        ])
        .map(mapField),
    [],
  );

  return (
    <FormSection title='产品资料配置'>
      <FieldCols
        form={form}
        fields={fields}
        colProps={useRef({ xs: 24, md: 24, xl: 24 }).current}
        wrapperSpan={24}
        labelSpan={0}
      />
    </FormSection>
  );
}

function DetailForm({ form }) {
  const fields = useMemo(
    () =>
      [
        [
          ['PE', 'attachmentUrl'],
          'Banner图',
          'named-upload',
          {
            accept: getAccept('image'),
            fileTypeProp: 'attachmentType',
            extra: '推荐尺寸 (750*300px @2x)',
          },
        ],
        [
          ['PC', 'attachmentUrl'],
          '产品特色',
          'named-upload',
          { accept: getAccept('image'), fileTypeProp: 'attachmentType' },
        ],

        [
          ['terms', 'attachmentUrl'],
          '产品条款',
          'named-upload',
          {
            accept: getAccept('pdf'),
            fileNameProp: 'richTextInfo',
            fileTypeProp: 'attachmentType',
            extra: '*附加险的产品条款请到"险种附件管理"页面进行配置',
          },
        ],

        /*[
         ['MV', 'attachmentUrl'],
         '音/视频介绍',
         'named-upload',
         { accept: getAccept('video', 'audio'), fileTypeProp: 'attachmentType' },
         ],*/
      ].map(mapField),
    [],
  );

  return (
    <FormSection title='产品详情配置'>
      <FieldCols form={form} fields={fields} />
    </FormSection>
  );
}

function EditAttachments(_, ref) {
  const productCodes = useProductCodesByPackageCode(usePackageData());
  const [form] = Form.useForm();

  const infoXhr = useReq(ProductInfoAPI.view);
  const clauseXhr = useReq(ProductAPI.getClause);
  const saveXhr = useReq((data) => Promise.all([saveInfoList(data), saveTerms(data)]));
  const isShow = Boolean(productCodes?.length);
  const isChangedRef = useRef(false);

  const allIdSet = useRef(new Set()).current;
  const singleMap = useRef(new Map()).current;
  const multiIdMap = useRef(new Map()).current;

  const infoData = infoXhr.result?.data;
  const clauseData = clauseXhr.result?.data;

  function saveInfoList(formData, options) {
    let singleList = productCodes.flatMap((code) =>
      singles
        .filter((v) => formData[v]?.attachmentUrl)
        .map((showType) => ({
          ...formData[showType],
          id: singleMap.get(`${code}:${showType}`),
          contentType: '2',
          relationCode: code,
          isShow: '1',
          showContentType: showType,
          showContentTitle: titleMap[showType],
        })),
    );

    let multiList = productCodes.flatMap((code) =>
      multiples
        .filter((v) => formData[v]?.list?.length)
        .flatMap((showType) =>
          formData[showType].list.map(({ name, url, ext }, index) => ({
            id: multiIdMap.get(`${code}:${showType}`)?.[index],
            richTextInfo: name,
            attachmentType: ext,
            attachmentUrl: url,
            contentType: '2',
            relationCode: code,
            isShow: '1',
            showContentType: showType,
            showContentTitle: titleMap[showType],
          })),
        ),
    );

    let infoList = [...singleList, ...multiList];

    infoList = infoList.filter((v) => {
      if (v.contentType === '2') return v.attachmentUrl;
      return v.richTextInfo;
    });
    const saveIds = new Set(infoList.map((v) => v.id || null));
    saveIds.delete(null);
    const delList = infoData?.filter((i) => !saveIds.has(i.id)) ?? [];

    return Promise.all([
      ...delList.map((item) => ProductInfoAPI.delete(item, options)),
      infoList.length ? ProductInfoAPI.insertOrUpdate(infoList, options) : Promise.resolve(),
    ]);
  }

  function saveTerms({ terms }, options) {
    let clauseList = productCodes.map((code) => ({
      id: singleMap.get(`${code}:terms`),
      relationCode: code,
      termsUrl: terms.attachmentUrl,
      termsName: terms.richTextInfo,
      termsType: terms.attachmentType,
      effectiveBeginTime: '1980-01-01 00:00:00',
      effectiveEndTime: '9999-12-31 23:59:59',
      effectiveLongTerm: '1',
    }));

    const saveIds = new Set(clauseList.map((v) => v.id || null));
    saveIds.delete(null);
    const delList = clauseData?.filter((i) => !saveIds.has(i.id)).map((v) => v.id) ?? [];
    const promise = [];

    if (delList.length) promise.push(ProductAPI.deleteClause(delList, options));
    promise.push(ProductAPI.updateClause(clauseList, options));

    return Promise.all(promise);
  }

  const onSave = useCall(() => {
    if (isChangedRef.current === false) return;

    let data = form.getFieldsValue();
    return saveXhr.start(data);
  });

  useEffect(() => {
    if (!isShow) return;

    const relationCode = productCodes.join(',');

    form.resetFields();
    form.setFieldsValue({ terms: {}, PE: {}, PC: {}, MV: {} });
    singleMap.clear();
    multiIdMap.clear();
    allIdSet.clear();
    infoXhr.start({
      relationCode: productCodes.join(','),
      showContentType: [...singles, ...multiples].join(','),
    });
    clauseXhr.start(relationCode);

    return () => {
      infoXhr.cancel();
      clauseXhr.cancel();
    };
  }, [isShow]);

  useEffect(() => {
    isChangedRef.current = true;
  }, [useFormValue(form)]);

  useEffect(() => {
    if (infoData) {
      const $pick = (v) => pick(v, ['attachmentUrl', 'attachmentType', 'richTextInfo'])[0];

      let codes = new Set();
      const formData = infoData.reduce((ret, data) => {
        const { showContentType: showType, id, relationCode: code } = data;
        const isSingle = singles.includes(showType);
        const key = `${code}:${showType}`;
        if (isSingle) singleMap.set(key, id);
        else multiIdMap.set(key, (multiIdMap.get(key) || []).concat([id]));
        allIdSet.add(id);
        codes.add(code);

        if (code !== productCodes[0]) return ret;
        if (isSingle) {
          ret[showType] ||= $pick(data);
          return ret;
        }
        const { richTextInfo: name, attachmentUrl: url, attachmentType: ext } = data;

        ret[showType] ||= { id: showType, list: [] };
        ret[showType].list.push({ id, name, url, ext });

        return ret;
      }, {});

      form.setFieldsValue(formData);

      let isChanged = productCodes.some((code) => !codes.has(code));
      setTimeout(() => {
        isChangedRef.current = isChanged;
      });
    }
  }, [infoData]);

  useEffect(() => {
    if (clauseData?.length) {
      clauseData.forEach((item) => {
        const key = `${item.relationCode}:terms`;
        singleMap.set(key, item.id);
      });
      let { termsName, termsUrl, termsType } = clauseData[0];
      termsName ||= basename(termsUrl);
      form.setFieldsValue({
        terms: {
          attachmentUrl: termsUrl,
          attachmentType: termsType,
          richTextInfo: termsName,
        },
      });
    }
  }, [clauseData]);

  useImperativeHandle(
    ref,
    () => ({
      onSave,
    }),
    [],
  );

  const loading = useDebounceValue([infoXhr.status, saveXhr.status].includes('loading'));

  return (
    <Spin spinning={loading}>
      <Form component={false} form={form}>
        <DetailForm form={form} />
        <FilesForm form={form} />
      </Form>
    </Spin>
  );
}

EditAttachments = forwardRef(EditAttachments);

export default EditAttachments;
